package com.fuyin.commons.aspect;

import com.fuyin.commons.aop.OperationLogAnnotation;
import com.fuyin.commons.response.BaseResponse;
import com.fuyin.commons.utils.JwtTokenUtil;
import com.fuyin.commons.utils.MyUtils;
import com.fuyin.dao.OperationLogDao;
import com.fuyin.entity.OperationLog;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Objects;

/**
 * @author yuanxilan (yuanxilan@keep.com)
 * @Description 自定义操作日志切面类，该类是将操作日志保存到数据库
 * @date 2021年11月28日 10:45 下午
 * @since
 */
@Aspect
@Component
@Slf4j
public class OperationLogAspect {

    @Autowired
    private OperationLogDao logDao;

    @Value("${jwt.tokenHead}")
    private String tokenHead;

    @Autowired
    private JwtTokenUtil jwtTokenUtil;

    private static HashMap<Integer, String> map = new HashMap<>();

    private static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    static {
        map.put(200, "操作成功");
        map.put(400, "请求出错");
        map.put(401, "没有登录");
        map.put(403, "没有权限");
        map.put(418, "抓取不到股票信息");
        map.put(421, "暂时不支持该股票的爬取");
    }

    /**
     * 设置操作日志切入点   在注解的位置切入代码
     */
    @Pointcut("@annotation(com.fuyin.commons.aop.OperationLogAnnotation)")
    public void operLogPoinCut() {
    }


    @AfterReturning(returning  /**
     * 记录操作日志
     * @param joinPoint 方法的执行点
     * @param result  方法返回值
     * @throws Throwable
     */ = "result", value = "operLogPoinCut()")
    public void saveOperLog(JoinPoint joinPoint, Object result) throws Throwable {
//        log.info("result: {}", result);
        // 获取RequestAttributes
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        // 从获取RequestAttributes中获取HttpServletRequest的信息
        HttpServletRequest request = (HttpServletRequest) requestAttributes.resolveReference(RequestAttributes.REFERENCE_REQUEST);
        if (Objects.isNull(request)) {
            log.error("com.fuyin.commons.aspect.OperationLogAspect.saveOperLog request is null");
            return;
        }
        try {
            //将返回值转换成map集合
//            Map<String, String> map = (Map<String, String>) result;
            BaseResponse response = (BaseResponse) result;
            OperationLog operationLog = new OperationLog();
            // 从切面织入点处通过反射机制获取织入点处的方法
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            //获取切入点所在的方法
            Method method = signature.getMethod();
            //获取操作
            OperationLogAnnotation annotation = method.getAnnotation(OperationLogAnnotation.class);
            if (annotation != null) {
                operationLog.setType(annotation.operType());
                operationLog.setDescription(annotation.operDesc());
            }
            //操作时间
            operationLog.setOperationTime(Timestamp.valueOf(sdf.format(new Date())));
            String token = request.getHeader("authorization");
            token = StringUtils.substring(token, tokenHead.length());
            String userName = request.getHeader("userName");
            if (StringUtils.isBlank(token) && StringUtils.isBlank(userName)) {
                log.error("请求中 token 或 userName 不能为空, URL:{}", request.getRequestURL().toString());
                return;
            }
            //操作用户
            if (StringUtils.isBlank(token)) {
                operationLog.setUserName(userName);
            } else {
                operationLog.setUserName(jwtTokenUtil.getUserNameFromToken(token));
            }
            //操作IP
            operationLog.setIp(MyUtils.getIpAddr(request));
            Integer code = ((BaseResponse<?>) result).getErrorCode();
            //返回值信息
            operationLog.setResult(map.get(code) == null ? "请求出错" : map.get(code));
            //保存日志
            logDao.save(operationLog);

        } catch (Exception e) {
//            e.printStackTrace();
            log.error("com.fuyin.commons.aspect.OperationLogAspect e:{}", e.getMessage());
        }
    }
}
